/**
 * Multicast project Bidois Morgan & Thomas Nunes
 *
 */
package middleware;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.ConcurrentModificationException;

/**
 *
 * @author thomas
 */
public class DataMulticastManager {

    private final int valueMax = 250;
    private ArrayList<DataMulticast> listMessages = new ArrayList<>();

    /**
     * Add an acquitement to a message
     *
     * @param lc the lc of the original message
     * @param id the id of the original message
     * @param clientWhoACK the client who ACK the message
     * @return if the message is deliver
     */
    public boolean addACK(int lc, int id, int clientWhoACK) {
        try {
            DataMulticast elt = this.get(lc, id);
            return elt.addClientWhoAckThis(clientWhoACK) && this.isPossible2deliver(lc);
        } catch (NullPointerException ne) {
        }
        return false;
    }

    public boolean contain(int lc, int id) {
        try{
        ArrayList<DataMulticast> list = (ArrayList<DataMulticast>) listMessages.clone();
        for (DataMulticast dm : list) {
            if (dm != null && dm.getIdClient() == id && dm.getLC() == lc) {
                return true;
            }
        }
        }catch(ConcurrentModificationException cme){
            
        }
        return false;
    }

    public DataMulticast get(int lc, int id) {
        ArrayList<DataMulticast> list = (ArrayList<DataMulticast>) listMessages.clone();
        for (DataMulticast dm : list) {
            if (dm.getIdClient() == id && dm.getLC() == lc) {
                return dm;
            }
        }
        return null;
    }

    public void add(DataMulticast dataMulticast) throws MessageWaitingOverflowException {
        if (listMessages.size() < valueMax) {
            listMessages.add(dataMulticast);
        } else {
            throw new MessageWaitingOverflowException();
        }
    }

    /**
     * Alert that a client is dead
     *
     * @param id the id of the dead client
     * @return 
     */
    public ArrayList<DataMulticast> notifyClientLeave(int id) {
        ArrayList<DataMulticast> message2deliver = new ArrayList<>();
        for (DataMulticast dm : listMessages) {
            if (dm.thisClientIsAFK(id)) {
                message2deliver.add(dm);
            }
        }
        return message2deliver;
    }

    void remove(int lCack, int iDack) {
        DataMulticast elt = this.get(lCack, iDack);
        listMessages.remove(elt);
    }

    /**
     * If it's possible to deliver considering if a previous message (lower
     * logical clock) wasn't send.
     *
     * @param lc the logical clock of the message to test
     * @return if this message is ready to deliver
     */
    private boolean isPossible2deliver(int lc) {
        boolean res = true;
        ArrayList<DataMulticast> list = (ArrayList<DataMulticast>) listMessages.clone();
        for (DataMulticast dm : list) {
            if (dm.getLC() < lc && !dm.isDeliver()) {
                return false;
            }
        }
        return res;
    }

    @Override
    public String toString() {
        String history = "";
        ArrayList<DataMulticast> list = (ArrayList<DataMulticast>) listMessages.clone();
        for (DataMulticast elt : list) {
            history += elt.toString();
        }
        return history;
    }

    ArrayList<DataMulticast> getAllMessageCanBeDeliver() {
        ArrayList<DataMulticast> ret = new ArrayList<>();
        ArrayList<DataMulticast> list = (ArrayList<DataMulticast>) listMessages.clone();
        for (DataMulticast dm : list) {
            if (dm != null && !dm.isDeliver() && dm.isPossible2Deliver()) {
                ret.add(dm);
            }
        }

        return ret;
    }
}

class ComparateurDataMulticast implements Comparator<DataMulticast> {

    @Override
    public int compare(DataMulticast t, DataMulticast t1) {
        if ((t.getLC()) > t1.getLC()) {
            return 1;
        } else {
            return -1;
        }
    }
}